package blue.http.internal.core.net;

import blue.base.core.util.AssertUtil;
import blue.http.core.HttpServer;
import blue.http.core.HttpServerBuilder;
import blue.http.core.options.HttpOptions;
import blue.http.core.options.ServerOptions;
import blue.http.core.options.SslOptions;
import blue.http.core.options.WebSocketOptions;
import blue.http.core.parser.FilterConfig;
import blue.http.core.parser.HttpUrlConfig;
import blue.http.core.parser.WebSocketUrlConfig;
import blue.http.core.plugin.SessionProvider;
import blue.http.internal.core.handler.HandlerFactory;
import blue.http.internal.core.mapping.HandlerMappingFactory;
import blue.http.internal.core.net.response.ResponseHandlerFactory;
import blue.http.internal.core.parser.ParserFactory;
import blue.http.internal.core.plugin.MemorySessionProvider;
import blue.http.internal.core.plugin.ProviderManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @author Jin Zheng
 * @since 1.0 2021-08-16
 */
public class DefaultHttpServerBuilder implements HttpServerBuilder {
	private static Logger logger = LoggerFactory.getLogger(DefaultHttpServerBuilder.class);

	private ServerOptions serverOptions;
	private HttpOptions httpOptions;
	private SslOptions sslOptions;
	private WebSocketOptions wsOptions;
	private SessionProvider sessionProvider;

	private final ProviderManager providerManager;
	private final ParserFactory parserFactory;
	private HandlerMappingFactory handlerMappingFactory;
	private HandlerFactory handlerFactory;
	private ResponseHandlerFactory responseHandlerFactory;

	public DefaultHttpServerBuilder() {
		parserFactory = new ParserFactory();
		providerManager = new ProviderManager(this);
	}

	@Override
	public HttpServer build() {
		AssertUtil.notNull(serverOptions, "ServerOptions");
		AssertUtil.notNull(httpOptions, "HttpOptions");

		providerManager.parse();

		if (sessionProvider == null) {
			sessionProvider = new MemorySessionProvider();
		}

		handlerMappingFactory = new HandlerMappingFactory(parserFactory);
		handlerFactory = new HandlerFactory();
		responseHandlerFactory = new ResponseHandlerFactory(httpOptions);

		HttpServer server = new DefaultHttpServer(this);
		return server;
	}

	@Override
	public HttpServerBuilder setServerOptions(ServerOptions options) {
		AssertUtil.notNull(options, "ServerOptions");
		options.check();
		this.serverOptions = options;
		return this;
	}

	@Override
	public HttpServerBuilder setHttpOptions(HttpOptions options) {
		AssertUtil.notNull(options, "HttpOptions");
		options.check();
		this.httpOptions = options;
		return this;
	}

	@Override
	public HttpServerBuilder setSslOptions(SslOptions options) {
		AssertUtil.notNull(options, "SslOptions");
		options.check();
		this.sslOptions = options;
		return this;
	}

	@Override
	public HttpServerBuilder setWebSocketOptions(WebSocketOptions options) {
		AssertUtil.notNull(options, "WebSocketOptions");
		options.check();
		this.wsOptions = options;
		return this;
	}

	@Override
	public HttpServerBuilder setSessionProvider(SessionProvider provider) {
		AssertUtil.notNull(provider, "SessionProvider");
		this.sessionProvider = provider;
		return this;
	}

	@Override
	public HttpServerBuilder addProvider(Object provider) {
		providerManager.addProvider(provider);
		return this;
	}

	@Override
	public HttpServerBuilder addHandler(Object handler) {
		AssertUtil.notNull(handler, "Controller or Filter");
		this.providerManager.addHandler(handler, handler.getClass());
		return this;
	}

	@Override
	public HttpServerBuilder addHandler(Object handler, Class<?> clazz) {
		AssertUtil.notNull(handler, "Controller or Filter");
		AssertUtil.notNull(clazz, "Controller or Filter class");
		this.providerManager.addHandler(handler, clazz);
		return this;
	}

	public ServerOptions getServerOptions() {
		return serverOptions;
	}

	public HttpOptions getHttpOptions() {
		return httpOptions;
	}

	public SslOptions getSslOptions() {
		return sslOptions;
	}

	public WebSocketOptions getWebSocketOptions() {
		return wsOptions;
	}

	public ParserFactory getParserFactory() {
		return parserFactory;
	}

	public HandlerMappingFactory getHandlerMappingFactory() {
		return handlerMappingFactory;
	}

	public HandlerFactory getHandlerFactory() {
		return handlerFactory;
	}

	public ResponseHandlerFactory getResponseHandlerFactory() {
		return responseHandlerFactory;
	}

	public SessionProvider getSessionProvider() {
		return sessionProvider;
	}

	public List<FilterConfig> getFilterConfigList() {
		return parserFactory.getFilterConfigCache().all();
	}

	public List<HttpUrlConfig> getHttpConfigList() {
		return parserFactory.getHttpConfigCache().all();
	}

	public List<WebSocketUrlConfig> getWebSocketConfigList() {
		return parserFactory.getWebSocketConfigCache().all();
	}

}
